
#include <errno.h>
#include <dirent.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_err.h"
#include "esp_log.h"
#include "lvgl.h"
#include "ad_key.h"
#include <sys/stat.h>

#include "image_processing.h"
#include "jpeg_decoder.h"
#include "cam.h"
#include "esp_lcd_ili9341.h"
#include "ui/ui.h"

#include "lodepng.h"

#include <sys/stat.h>
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_host.h"
#include "sd_test_io.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
#include "esp_heap_caps.h"
#include "ds1302.h"

#include "sdkconfig.h"
#include "esp_console.h"
#include "esp_check.h"
#include "esp_partition.h"
#include "driver/gpio.h"
#include "tinyusb.h"
#include "tusb_msc_storage.h"
#include "diskio_impl.h"
#include "diskio_sdmmc.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
//spi选择
#define LCD_HOST  SPI2_HOST
//引脚定义
#define EXAMPLE_PIN_NUM_MOSI     47
#define EXAMPLE_PIN_NUM_SCLK     21
#define EXAMPLE_PIN_NUM_LCD_CS   44
#define EXAMPLE_PIN_NUM_LCD_DC   43
#define EXAMPLE_PIN_NUM_BK_LIGHT 48
#define EXAMPLE_PIN_NUM_LCD_RST  -1
//屏幕尺寸
#define EXAMPLE_LCD_H_RES              320
#define EXAMPLE_LCD_V_RES              240

//lvgl触发周期
#define EXAMPLE_LVGL_TICK_PERIOD_MS    2
//lvgl任务参数
#define EXAMPLE_LVGL_TASK_MAX_DELAY_MS 500
#define EXAMPLE_LVGL_TASK_MIN_DELAY_MS 2
#define EXAMPLE_LVGL_TASK_STACK_SIZE   (80 * 1024)
#define EXAMPLE_LVGL_TASK_PRIORITY     2

#define EXAMPLE_MAX_CHAR_SIZE    64 //最大输入
#define MOUNT_POINT "/sdcard"       //挂载点
// #define PSRAM_ATTR __attribute__((section(".ext_ram.data")))


int g_file_count = 0;
bool del_pict = 0;
uint16_t save_picture_num = 0;
uint16_t read_picture_num = 1;
uint16_t sd_img_num = 1;
uint8_t bsp_key_num = 0 ;
lv_group_t *bsp_s1_group;
lv_group_t *bsp_s2_group;
lv_group_t *bsp_s3_group;
lv_group_t *bsp_s4_group;
lv_group_t *bsp_s5_group;

lv_indev_t *keypad_indev;
uint8_t bsp_cam_state = 0;
uint8_t PIC_CAP = 0 ;
esp_err_t ret;
sdmmc_card_t *card;
char name_member[30];
bool fst = 0;
uint8_t out_value = 0;

uint8_t save_number = 0;
uint16_t *bsp_decode_camera = 0;
uint16_t *bsp_decode_sdcard = 0;
uint8_t *bsp_jpeg = NULL;
uint8_t *bsp_cam_jpeg = NULL;
size_t bsp_jpeg_size = 0;
uint8_t album_state = 0;
uint8_t pict_name_get = 0;
uint16_t * decoded_pixels = NULL;
const char mount_point[] = MOUNT_POINT;

uint8_t dis_recap = 0;
uint8_t save_csv_bit = 0;
uint8_t fs_big = 0;

lv_img_dsc_t picture_show = {
                .header.always_zero = 0,
                .header.w = 240,
                .header.h = 240,
                .header.cf = LV_IMG_CF_TRUE_COLOR,
            };

bsp_time_t first_setime = {
    .year = 25,
    .month = 7,
    .week = 4,
    .day = 3,
    .hour = 15,
    .minute = 57,
    .second = 24
};

typedef struct {
    char *time;
    char *train;
    char *status;
    char *picture_name;
} scv_elements_t;

typedef struct {
    unsigned char *data;
    size_t size;
} PngData;

//全局静态变量，用于输出打印log
static const char *TAG = "main";

//用于确保同一时间只有一个任务能够进行LVGL操作
static SemaphoreHandle_t lvgl_mux = NULL;

typedef struct {
    int index; 
    char filename[30];
} BinFile;
BinFile g_files[2000];

int compare_files(const void *a, const void *b) {
    return ((BinFile *)a)->index - ((BinFile *)b)->index;
}

void list_and_sort_bin_files(const char *dir_path) {
    DIR *dir = opendir(dir_path);
    if (!dir) {
    printf("Failed to open directory: %s\n", dir_path);
    return;
    }
    g_file_count = 0;
    struct dirent *entry;

    while ((entry = readdir(dir)) != NULL && g_file_count < 2000) {
        const char *ext = strrchr(entry->d_name, '.');
        if (!ext || strcmp(ext, ".png") != 0) continue;

        int index = atoi(entry->d_name);
        if (index == 0) continue;

        strncpy(g_files[g_file_count].filename, entry->d_name, sizeof(g_files[0].filename));
        g_files[g_file_count].index = index;
        g_file_count++;
    }
    closedir(dir);

    qsort(g_files, g_file_count, sizeof(BinFile), compare_files);
}
//将rgb565解码成png
PngData encode565_to_png (uint8_t *picture565){
    // 先将图片从565转888
    uint8_t *picture888 = malloc(240 * 240 * 3);
    for(uint16_t count = 0; count < 240 * 240; count ++)
    {
        uint16_t pixel = (picture565[count * 2]<<8) | picture565[count * 2 + 1];
        picture888[count * 3 + 0] = ( pixel >> 8 ) & 0xf8;
        picture888[count * 3 + 1] = ( pixel >> 3 ) & 0xfc;
        picture888[count * 3 + 2] = ( pixel << 3 ) & 0xf8;
    }
    // 转换结束，并将转换后的数据储存到picture888中
    // 开始将rgb888转为png格式
    PngData png = {
        .data = NULL,
        .size = 0
    };
    unsigned error = lodepng_encode24(&png.data, &png.size, picture888, 240, 240);
    free(picture888);
    if (error) {
        printf("PNG error: %s\n", lodepng_error_text(error));
        png.data = NULL; // 确保错误时 data 为 NULL
        png.size = 0;
    }
    return png;
}
// png转rgb565函数
uint8_t *png_rgb888(uint8_t *png_buf, size_t png_size ){
    uint8_t *rgb888_buf = NULL;
    uint8_t* rgb565_buf = (uint8_t*)malloc(240 * 240 * 2);
    unsigned wh_w = 240;
    unsigned wh_h = 240;
    unsigned error = lodepng_decode24(&rgb888_buf, &wh_w, &wh_h, png_buf, png_size);
    if (error) {
        free(rgb565_buf);
        printf("PNG解码错误 %u: %s\n", error, lodepng_error_text(error));
        return NULL;
    }
    for (int i = 0; i < 240 * 240; i++) {
        uint8_t r = rgb888_buf[i * 3 + 0]; // R
        uint8_t g = rgb888_buf[i * 3 + 1]; // G
        uint8_t b = rgb888_buf[i * 3 + 2]; // B
        uint16_t rgb565 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
        
        // 将uint16_t拆解为两个uint8_t（注意字节序）
        rgb565_buf[i * 2] = (rgb565 >> 8);    // 高字节在前
        rgb565_buf[i * 2 + 1] = rgb565 & 0xFF; // 低字节在后
    }
    free(rgb888_buf);
    return rgb565_buf;
}
// 将捕获的png图像保存到sd卡中
static esp_err_t save_jpeg_to_sd(const char *path, uint8_t *data, size_t size) {
    ESP_LOGI(TAG, "Saving JPEG to: %s", path);
    
    // 以二进制写入模式打开文件,如果没有文件，便创建文件
    FILE *f = fopen(path, "wb");
    // 判断文件是否创建成功
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for writing");
        return ESP_FAIL;
    }
    
    // 写入二进制数据
    size_t written = fwrite(data, 1, size, f);
    fclose(f);
    
    // 验证写入完整性
    if (written != size) {
        ESP_LOGE(TAG, "Write failed (expected %d, written %d)", size, written);
        return ESP_FAIL;
    }
    
    ESP_LOGI(TAG, "JPEG saved successfully (%d bytes)", written);
    return ESP_OK;
}
// 检测sd卡中是否有Detection_records.csv文件，如果没有，创建一个并写入表头，如果有，忽略
static esp_err_t bsp_creat_csv (void){
    char *header = "Time,Train,State,Picture_name";
    char *path  = MOUNT_POINT"/Detection_records.csv";
    ESP_LOGI(TAG,"Creat csv file to %s",path);
    struct stat st;
    if( stat(path,&st) !=0 ){
        FILE *f = fopen(path,"w");
        if(f == NULL){
            ESP_LOGE(TAG , "failed to create csv file(w)");
            return ESP_FAIL;
        }
        fprintf(f,"%s\n",header);
        fclose(f);
    }
    return ESP_OK;
}
// 在csv文件中写入新内容，调用前先新建一个csv_elements_t结构体，并定义数值，后将结构图传入函数中
static esp_err_t bsp_write_csv(scv_elements_t write_data)
{
    char *path  = MOUNT_POINT"/Detection_records.csv";
    char csv_data[256];
    ESP_LOGI(TAG,"Write csv file to %s",path);
    snprintf(csv_data, 256, "%s,%s,%s,%s", 
            write_data.time, write_data.train,write_data.status,write_data.picture_name);
    FILE *f = fopen(path, "a");
    if(f == NULL){
            ESP_LOGE(TAG , "failed to open csv file(a)");
            return ESP_FAIL;
    }
    fprintf(f, "%s\n",csv_data);
    fclose(f);
    ESP_LOGI(TAG, "The file was written successfully");
    return ESP_OK;
}
// 屏幕初始化命令
static const ili9341_lcd_init_cmd_t lcd_init_cmds[] = {
    /* {cmd, { data }, data_size, delay_ms} */ 
    {0x11, (uint8_t []){0x00}, 1, 120},
    {0x36, (uint8_t []){0xA0}, 1, 0},
    {0xB2, (uint8_t []){0x0B, 0x0B, 0x00, 0x33, 0x33}, 5, 0},
    {0xB7, (uint8_t []){0x11}, 1, 0},
    {0xBB, (uint8_t []){0x2F}, 1, 0},
    {0xC0, (uint8_t []){0x2C}, 1, 0},
    {0xC2, (uint8_t []){0x01}, 1, 0},
    {0xC3, (uint8_t []){0x0D}, 1, 0},
    {0xC4, (uint8_t []){0x20}, 1, 0},
    {0xC6, (uint8_t []){0x13}, 1, 0},
    {0xD0, (uint8_t []){0xA4, 0xA1}, 2, 0},
    {0xD6, (uint8_t []){0xA1}, 1, 0},
    {0xE0, (uint8_t []){0xF0, 0x04, 0x07, 0x09, 0x07, 0x13, 0x25, 0x33, 0x3C, 0x34, 0x10, 0x10, 0x29, 0x32}, 14, 0},
    {0xE1, (uint8_t []){0xF0, 0x05, 0x08, 0x0A, 0x09, 0x05, 0x25, 0x32, 0x3B, 0x3B, 0x17, 0x18, 0x2E, 0x37}, 14, 0},
    {0xE4, (uint8_t []){0x25, 0x00, 0x00}, 3, 0},
    {0x21, (uint8_t []){0x00}, 1, 0},
    {0x2A, (uint8_t []){0x00, 0x00, 0x01, 0x3F}, 4, 0},
    {0x2B, (uint8_t []){0x00, 0x00, 0x00, 0xEF}, 4, 0},
    {0x2C, (uint8_t []){0x00}, 1, 0},
    {0x29, (uint8_t []){0x00}, 1, 0},
};
//回调函数，用于在颜色传输完成时被调用
static bool example_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
    lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx;
    lv_disp_flush_ready(disp_driver);//通知lvgl绘图操作已经完成
    return false;//返回false表示在刷新完成后lvgl不需要等待额外的处理
}
//刷新显示时的回调函数
static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
{
    esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data;
    int offsetx1 = area->x1;
    int offsetx2 = area->x2;
    int offsety1 = area->y1;
    int offsety2 = area->y2;
    /* Copy a buffer's content to a specific area of the display */
    esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
}

static void example_increase_lvgl_tick(void *arg)
{
    /* Tell LVGL how many milliseconds has elapsed */
    lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);
}
//按键回调函数
static void example_lvgl_keypad_cb(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
    static uint32_t last_key = 0;
    static bool key_pressed = false;
    static uint32_t last_press_time = 0;
    const uint32_t debounce_delay = 200; // 消抖时间20ms

    int raw_key = bsp_adkey_read();
    uint32_t current_time = xTaskGetTickCount() * portTICK_PERIOD_MS;

    // 消抖逻辑：仅在稳定按下或释放时更新状态
    if (raw_key != 0) {
        if (!key_pressed && (current_time - last_press_time > debounce_delay)) {
            key_pressed = true;
            last_press_time = current_time;
        }
    } else {
        if (key_pressed) {
            key_pressed = false;
            last_press_time = current_time;
        }
    }
    if (key_pressed) {
        data->state = LV_INDEV_STATE_PRESSED;
        switch (raw_key) {
            case 1: if(lv_group_get_editing(bsp_s1_group)){
                data->key = 0;
            }else data->key = LV_KEY_PREV;          break;   // 假设按键1对应"下一个" 
            case 2:if(lv_group_get_editing(bsp_s1_group)){
                data->key = 0;
            }else data->key = LV_KEY_NEXT;          break;  // 按键2对应"上一个"
            case 3: data->key = LV_KEY_ENTER;       break; // 按键3对应左键
            case 4: data->key = LV_KEY_LEFT;        break; // 按键4对应右键
            case 5: data->key = LV_KEY_RIGHT;       break; // 按键5对应确定
            default: data->key = 0;                 break; // 未知按键
        }
        last_key = data->key;
        printf("%ld\n",last_key);
    } else {
        data->state = LV_INDEV_STATE_RELEASED;
        data->key = last_key; // 释放时传递最后一次按下的键值（可选）
    }

}

static bool example_lvgl_lock(int timeout_ms)
{
    assert(lvgl_mux && "bsp_display_start must be called first");

    const TickType_t timeout_ticks = (timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
    return xSemaphoreTake(lvgl_mux, timeout_ticks) == pdTRUE;
}

static void example_lvgl_unlock(void)
{
    assert(lvgl_mux && "bsp_display_start must be called first");
    xSemaphoreGive(lvgl_mux);
}

static esp_err_t save_picture_number(void){

    char num_of_picture[64];
    snprintf(num_of_picture, sizeof(num_of_picture), "%s/number.bin", MOUNT_POINT);
    ESP_LOGI(TAG, "Saving number of pictures to: %s", num_of_picture);

    FILE *f = fopen(num_of_picture, "wb");
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for writing");
        return ESP_FAIL;
    }
    fwrite(&save_picture_num, 1, sizeof(uint16_t), f);
    fclose(f);

    ESP_LOGI(TAG, "Loaded picture count: %u", &save_picture_num);
    return ESP_OK;
}

static esp_err_t read_picture_number(void){
    char num_of_picture[64];
    snprintf(num_of_picture, sizeof(num_of_picture), "%s/number.bin", MOUNT_POINT);
    ESP_LOGI(TAG, "Saving number of pictures to: %s", num_of_picture);
    FILE *file = fopen(num_of_picture, "wb");
    if (!file) {
        ESP_LOGE("PNG", "Failed to open file: %s", num_of_picture);
        return ESP_FAIL;
    }
    fread(&save_picture_num, 1, sizeof(uint16_t), file);
    return ESP_OK;
}

//读取sd卡中的jpg照片
uint8_t *read_jpeg_file(const char *path, size_t *out_size) {
    FILE *file = fopen(path, "rb");
    if (!file) {
        ESP_LOGE("JPEG", "Failed to open file: %s", path);
        return NULL;
    }

    // 获取文件大小
    fseek(file, 0, SEEK_END);
    *out_size = ftell(file);
    fseek(file, 0, SEEK_SET);

    // 分配内存并读取文件
    uint8_t *data = malloc(*out_size);
    if (!data) {
        fclose(file);
        return NULL;
    }
    fread(data, 1, *out_size, file);
    fclose(file);

    return data;
}



int map_adc_value(int adc_value) {
    if(adc_value <= 300) return 0;
    if(adc_value >= 1500) return 100;
    return (adc_value - 300) * 100 / 1200; // 1200 = 1500-300
}
    


uint8_t i = 0 ;
//LVGL任务函数
static void example_lvgl_port_task(void *arg)
{
    ESP_LOGI(TAG, "Starting LVGL task");
    //初始化ui界面
    ui_init();
    lv_group_add_obj(bsp_s1_group, ui_Dropdown1);
    lv_group_add_obj(bsp_s1_group, ui_carnum);
    lv_group_add_obj(bsp_s1_group, ui_S1L);
    lv_group_add_obj(bsp_s1_group, ui_S1R);
    lv_group_add_obj(bsp_s1_group, ui_Keyboard2);

    lv_group_add_obj(bsp_s2_group, ui_S2L);
    lv_group_add_obj(bsp_s2_group, ui_S2R);

    lv_group_add_obj(bsp_s3_group, ui_S3L);
    lv_group_add_obj(bsp_s3_group, ui_S3R);

    lv_group_add_obj(bsp_s4_group, ui_S4L);
    lv_group_add_obj(bsp_s4_group, ui_S4M);
    lv_group_add_obj(bsp_s4_group, ui_S4R);

    lv_group_add_obj(bsp_s5_group, ui_S5L);
    lv_group_add_obj(bsp_s5_group, ui_S5M);
    lv_group_add_obj(bsp_s5_group, ui_S5R);
    lv_group_add_obj(bsp_s5_group, ui_PGUP);
    lv_group_add_obj(bsp_s5_group, ui_PGDN);
    lv_group_focus_obj(ui_Dropdown1);
     
    lv_indev_set_group(keypad_indev, bsp_s1_group); 
    uint32_t task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS;
     cam_setup();
    camera_fb_t *fb = NULL;

    while (1) {
        // Lock the mutex due to the LVGL APIs are not thread-safe
        if (example_lvgl_lock(-1)) {
            task_delay_ms = lv_timer_handler();
            // Release the mutex
            example_lvgl_unlock();
        }
        if (task_delay_ms > EXAMPLE_LVGL_TASK_MAX_DELAY_MS) {
            task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS;
        } else if (task_delay_ms < EXAMPLE_LVGL_TASK_MIN_DELAY_MS) {
            task_delay_ms = EXAMPLE_LVGL_TASK_MIN_DELAY_MS;
        }
        if(fst){
            int fsnum_get = bsp_adfs_read();
            out_value = map_adc_value(fsnum_get);
            lv_arc_set_value(ui_Arc1, out_value);
            lv_label_set_text_fmt(ui_Label8, "%d",out_value);
            printf("fengsu_num = %d \n",fsnum_get);
        }
        if(bsp_cam_state){
            fb = esp_camera_fb_get();
            picture_show.data_size = fb->len ;
            picture_show.data = fb->buf ;
            lv_img_set_src(ui_Image6,&picture_show);
            esp_camera_fb_return(fb);
            fb = NULL;
            
            if(PIC_CAP){
                fb = esp_camera_fb_get();
                if (fb) {
                    save_picture_num ++;
                    char pict_name_part1[32];
                    bsp_time_t getime =  DS1302_Read_Time();
                    sniprintf(pict_name_part1,sizeof(pict_name_part1),"20%d_%d_%d_%d_%d", getime.year,getime.month,getime.day,getime.hour,getime.minute);
                    PngData getpng = encode565_to_png(fb->buf);
                    char write_file_path[128];
                    snprintf(write_file_path, sizeof(write_file_path), "%s/%d_%s_%s.png", MOUNT_POINT,save_picture_num,name_member,pict_name_part1);
                    ret = save_jpeg_to_sd(write_file_path, getpng.data, getpng.size);
                    scv_elements_t write_elements = {
                        .time               = pict_name_part1,
                        .train              = name_member,
                        .status             = "There is an air leak",
                        .picture_name       = write_file_path
                    };
                    bsp_write_csv(write_elements);
                    if (ret != ESP_OK) {
                    ESP_LOGE(TAG, "Failed to save JPEG");
                    }
                }
                esp_camera_fb_return(fb);
                PIC_CAP = 0;
            }
        }
        if(save_number){
            ret = save_picture_number();
            save_number = 0;
        }
        if(del_pict){
                char read_file_path[64];
                snprintf(read_file_path,sizeof(read_file_path),"%s/%s", MOUNT_POINT, g_files[read_picture_num-1].filename);
                unlink(read_file_path);
                del_pict = 0;
                pict_name_get = 1;
                album_state = 1;
                save_number = 1;
        }
        if(album_state){
            if(pict_name_get){
                list_and_sort_bin_files("/sdcard");
                pict_name_get = 0;
                printf("the picture number is %d\n",g_file_count);
                if(read_picture_num>g_file_count){
                    read_picture_num = 1;
                }
            }
            char read_file_path[128];
            printf("%s",g_files[read_picture_num-1].filename);
            lv_label_set_text_fmt(ui_Label13,"%s",g_files[read_picture_num-1].filename);
            printf("%d\n",read_picture_num);
            snprintf(read_file_path,128,"%s/%s", MOUNT_POINT, g_files[read_picture_num-1].filename);
            bsp_jpeg = read_jpeg_file(read_file_path, &bsp_jpeg_size);
            uint8_t *read_png = png_rgb888(bsp_jpeg, bsp_jpeg_size);
            if (read_png == NULL || bsp_jpeg_size == 0) {
                ESP_LOGE("MAIN", "Failed to read JPEG file");
            } else {
                ESP_LOGI("MAIN", "Read JPEG file, size: %d bytes", bsp_jpeg_size);
            }
            picture_show.data_size = 240*240*2;
            picture_show.header.cf = LV_IMG_CF_TRUE_COLOR;
            picture_show.data = (const uint8_t *)read_png;
            lv_img_set_src(ui_Image1,&picture_show);
            free(bsp_jpeg);
            if (read_png) free(read_png);
            album_state = 0;
            
        }
        if(save_csv_bit){
            bsp_time_t getime =  DS1302_Read_Time();
            char timebuf[64];
            snprintf(timebuf, sizeof(timebuf), "20%d/%d/%d/%d:%d", getime.year,getime.month,getime.day,getime.hour,getime.minute);
            scv_elements_t write_elements = {
                .time               = timebuf,
                .train              = name_member,
                .status             = "There are no air leaks",
                .picture_name       = "No photos"
            };
            bsp_write_csv(write_elements);
            save_csv_bit = 0;

        }
        vTaskDelay(pdMS_TO_TICKS(task_delay_ms));
    }
}
// 初始化sd卡
void sdmmc_init(void)
{

    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
        .format_if_mount_failed = true,
        .max_files = 5,
        .allocation_unit_size = 16 * 1024
    };
    
    ESP_LOGI(TAG, "Initializing SD card");
    ESP_LOGI(TAG, "Using SDMMC peripheral");
    sdmmc_host_t host = SDMMC_HOST_DEFAULT();
    sdmmc_slot_config_t slot_config ;
    slot_config.width = 1;
    slot_config.clk = 39;
    slot_config.cmd = 40;
    slot_config.d0 = 38;
    slot_config.cd = SDMMC_SLOT_NO_CD, 
    slot_config.wp = SDMMC_SLOT_NO_WP,
    slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
    ESP_LOGI(TAG, "Mounting filesystem");
    ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);

    if (ret != ESP_OK) {
        if (ret == ESP_FAIL) {
            ESP_LOGE(TAG, "Failed to mount filesystem. "
                    "If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
        } else {
            ESP_LOGE(TAG, "Failed to initialize the card (%s). "
                    "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
            }
            return;
    }
    ESP_LOGI(TAG, "Filesystem mounted");
    //用于打印sd卡信息
    sdmmc_card_print_info(stdout, card);
}

void print_all_tasks() {
    char buf[1024];
    vTaskList(buf);
    ESP_LOGI(TAG, "Tasks:\n%s", buf);
}

void app_main(void)
{
    ESP_LOGI(TAG,"device on");
    size_t free_psram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
    ESP_LOGI(TAG, "Free PSRAM: %d bytes", free_psram); 
    sdmmc_init();
/*******************************初始化ds1302**************************/
    ds1302_gpio_init();  
    // 设置DS1302时间
    ds1302_set_alltime(first_setime);
/**************SD卡相关操作，写入读取bin文件，创建csv文件 **************/
    read_picture_number();
    printf("%d\n",save_picture_num);
    bsp_creat_csv ();
/********************************LVGL*****************************/
    static lv_disp_draw_buf_t disp_buf;
    static lv_disp_drv_t disp_drv;//配置和定义显示驱动的参数，在这里主要用来给example_notify_lvgl_flush_ready函数传参
    ESP_LOGI(TAG, "Initialize SPI bus");
    const spi_bus_config_t buscfg = ILI9341_PANEL_BUS_SPI_CONFIG( EXAMPLE_PIN_NUM_SCLK, EXAMPLE_PIN_NUM_MOSI,
                                                            EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES * sizeof(uint16_t));
    ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));

    ESP_LOGI(TAG, "Install panel IO");
    esp_lcd_panel_io_handle_t io_handle = NULL;
    const esp_lcd_panel_io_spi_config_t io_config = ILI9341_PANEL_IO_SPI_CONFIG(EXAMPLE_PIN_NUM_LCD_CS, EXAMPLE_PIN_NUM_LCD_DC,
                                                                                example_notify_lvgl_flush_ready, &disp_drv);
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));

    ESP_LOGI(TAG, "Install ILI9341 panel driver");
    esp_lcd_panel_handle_t panel_handle = NULL;
    ili9341_vendor_config_t vendor_config = {  // Uncomment these lines if use custom initialization commands
        .init_cmds = lcd_init_cmds,
        .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(ili9341_lcd_init_cmd_t),
    };
    const esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST,      // Set to -1 if not use
        .rgb_endian = LCD_RGB_ENDIAN_RGB,
        .bits_per_pixel = 16,                           // Implemented by LCD command `3Ah` (16/18)
        // .vendor_config = &vendor_config,            // Uncomment this line if use custom initialization commands
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true ,false));
    ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
    ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, false));
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, false));
    ESP_LOGI(TAG, "Initialize LVGL");

    lv_init();
    
    /* Alloc draw buffers used by LVGL */
    /* It's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized */
    lv_color_t *buf1 = (lv_color_t *)heap_caps_malloc(EXAMPLE_LCD_H_RES * 50 *sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1);
    lv_color_t *buf2 = (lv_color_t *)heap_caps_malloc(EXAMPLE_LCD_H_RES * 50 *sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf2);
    /* Initialize LVGL draw buffers */
    lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 50);

    ESP_LOGI(TAG, "Register display driver to LVGL");

    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res    = EXAMPLE_LCD_H_RES;
    disp_drv.ver_res    = EXAMPLE_LCD_V_RES;
    disp_drv.flush_cb   = example_lvgl_flush_cb;
    disp_drv.draw_buf   = &disp_buf;
    disp_drv.user_data  = panel_handle;
    lv_disp_t *disp     = lv_disp_drv_register(&disp_drv);

    ESP_LOGI(TAG, "Register KeyPad driver to LVGL");
    static lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type           = LV_INDEV_TYPE_KEYPAD;
    indev_drv.disp           = disp;
    indev_drv.read_cb        = example_lvgl_keypad_cb;
    keypad_indev = lv_indev_drv_register(&indev_drv);
    bsp_s1_group = lv_group_create();
    bsp_s2_group = lv_group_create();
    bsp_s3_group = lv_group_create();
    bsp_s4_group = lv_group_create();
    bsp_s5_group = lv_group_create();

    //lv_group_set_default(bsp_group);
    
    ESP_LOGI(TAG, "Install LVGL tick timer");

    /* Tick interface for LVGL (using esp_timer to generate 2ms periodic event) */
    const esp_timer_create_args_t lvgl_tick_timer_args = {
        .callback   = &example_increase_lvgl_tick,
        .name       = "lvgl_tick"
    };
    esp_timer_handle_t lvgl_tick_timer = NULL;
    ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));

    ESP_LOGI(TAG, "Create LVGL task");
    lvgl_mux = xSemaphoreCreateMutex();
    assert(lvgl_mux);
    bsp_adkey_init();
    bsp_adfs_init();
    //任务创建
    BaseType_t ret = xTaskCreate(example_lvgl_port_task, "LVGL", EXAMPLE_LVGL_TASK_STACK_SIZE, NULL, 5, NULL);
    if (ret != pdPASS) {
        ESP_LOGE(TAG, "Failed to create LVGL task! Free heap: %d", esp_get_free_heap_size());
    }    
    vTaskDelay(400 / portTICK_PERIOD_MS);
    // printf("usb_state is %d \n",usb_state);
    
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
    print_all_tasks();
    // }
}